
package com.netease.xone.widget.msgbubble;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * SurfaceView渲染类，维护一个绘制线程，负责控制一些绘制流程，使用setRender(Renderable)执行具体操作
 *
 * @author MR
 */
public class RenderSurface extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "RenderSurface";
    public static final boolean DEBUG = false;

    private MyThread mThread;
    private Renderable mRender;


    public RenderSurface(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public RenderSurface(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RenderSurface(Context context) {
        this(context, null, 0);
    }

    public void setRender(Renderable render) {
        mRender = render;
    }

    private void init() {
        getHolder().addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (DEBUG) {
            Log.d("RenderSurface", "surfaceChanged");
        }
        if (mRender != null)
            mRender.onSurfaceChanged(width, height);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (DEBUG) {
            Log.d("RenderSurface", "surfaceCreated");
        }
        final int width = getWidth();
        final int height = getHeight();
        mRender.onSurfaceCreated(width, height);
        mThread = new MyThread(getHolder());
        if (mRender != null)
            mThread.setRender(mRender);
        mThread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (DEBUG) {
            Log.d("RenderSurface", "surfaceDestroyed");
        }
        mThread.isRunning = false;
        boolean retry = true;
        while (retry) {
            try {
                mThread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }

    public void setWillDraw(boolean willDraw) {
        if(mThread != null){
            mThread.setWillDraw(willDraw);
        }
    }

    private static class MyThread extends Thread {

        private boolean isRunning;

        private long mLast = 0;

        private SurfaceHolder holder;

        private Renderable mRender;

        private boolean mWillDraw;

        public void setWillDraw(boolean willDraw) {
            mWillDraw = willDraw;
        }

        public MyThread(SurfaceHolder holder) {
            this.holder = holder;
            isRunning = true;
            mWillDraw = true;
        }

        @Override
        public void run() {
            while (isRunning) {
                if (mRender != null) {
                    Canvas c = null;
                    mRender.updateState();
                    if (mWillDraw) {
                        try {
                            c = holder.lockCanvas();
                            synchronized (holder) {
                                if (c != null) {
                                    mRender.doDraw(c);
                                }
                            }
                        } finally {
                            if (c != null) {
                                holder.unlockCanvasAndPost(c);
                            }
                        }
                    }
                    mLast = waitToInterval(mLast);
                } else {
                    throw new IllegalStateException(
                            "RenderSurface:renderAdapter can not be null!call setRender() to set one");
                }
            }
        }

        private long waitToInterval(long last) {
            long now = System.currentTimeMillis();
            long interval = now - last;
            if (interval < 1000 / mRender.getFrameHz()) {
                try {
                    if (DEBUG) {
                        Log.v(TAG, "need sleep interval:" + interval);
                    }
                    Thread.sleep(interval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                if (DEBUG) {
                    Log.v(TAG, "no need sleep interval:" + interval);
                }
            }
            return now;
        }

        public void setRender(Renderable render) {
            mRender = render;
        }
    }
}
